package com.pzl.compiler;

import com.google.auto.service.AutoService;
import com.pzl.router.RouterPath;

import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;

/**
 *
 * 先看“componentJump”工程，目的：解析注解获取定义的path路径（key）,编译时帮各组件（module）
 * 生成工具类（工具类作用：把各自module的activity class 缓存到单例容器）
 *
 * 编译时动态生成类 (在工程里面全局搜索工具类名字，如：ActivityClassUtil ，就能发现是否成功生成Java源文件)
 */
@AutoService(Processor.class)//注册该类为注解处理器
public class AnnotationCompiler extends AbstractProcessor {
    //生成代码的工具类
    Filer filer;
    //日志打印类，Log使用不了，编译时
    Messager messager;


    /**
     *  申明该注解处理器需要处理的注解有哪些(处理器扫描是就只处理这些类型的注解)
     * @return
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new HashSet<>();
        String type = RouterPath.class.getCanonicalName();
        types.add(type);
        return types;
    }

    /**
     *  注解处理器支持的Java版本
     * @return
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        //processingEnv 处理器环境 存在于父类
        return  processingEnv.getSourceVersion();
    }

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        filer = processingEnvironment.getFiler();
        messager = processingEnvironment.getMessager();
    }

    /**
     * 注解处理的核心方法，我们的目的是需要生成工具类的源代码
     * @param set
     * @param roundEnvironment
     * @return
     */
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        //获取被RouterPath注解标注的节点
        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(RouterPath.class);
        Map<String,String> map = new HashMap<>();
        //TypeElement 类节点元素
        //ExecutableElement 方法节点元素
        //VariableElement 成员变量节点元素
        for (Element element : elements) {
            TypeElement typeElement = (TypeElement) element;
            //获取类节点元素标识类的包名路径
            String activityName = typeElement.getQualifiedName().toString();
            //获取注解参数值
            String key = typeElement.getAnnotation(RouterPath.class).value();
            map.put(key,activityName+".class");//跳转路径名称、activity class 全限定包名
            messager.printMessage(Diagnostic.Kind.NOTE,"jinx : 路径-activity类 注册 path = "+key+ " , activityName = "+activityName);
        }

        //生成各组件（module）工具类源码
        if(map.size() >0){
            Writer writer = null;
            //工具类所在的包名在各组件工程中都统一使用相同名称（方便路由框架找到工具类）
            // 各组件工程类名称追加时间戳区别，以防类冲突
            String className = "ActivityClassUtil"+System.currentTimeMillis();
            try {
                JavaFileObject sourceFile = filer.createSourceFile(
                        "com.pzl.path.util." + className);//书写Java源代码 生成Java源文件
                writer = sourceFile.openWriter();
                StringBuffer stringBuffer = new StringBuffer();//这里可以先把工具类写出来，然后一行行粘贴
                stringBuffer.append("package com.pzl.path.util;\n");
                stringBuffer.append("import com.pzl.router.IJump;\n");
                stringBuffer.append("import com.pzl.router.JumpUtil;\n");
                //activity使用全限定名称，这里就不导入了
                stringBuffer.append("public class "+className+" implements IJump {\n");
                stringBuffer.append("@Override\n");
                stringBuffer.append(" public void saveActivityClass() {\n");
                Iterator<String> iterator = map.keySet().iterator();
                while (iterator.hasNext()){
                    String key = iterator.next();
                    String activityName = map.get(key);
                    stringBuffer.append("JumpUtil.getInstance().saveActivityClass(\""+key+"\","+activityName+");");
                }
                stringBuffer.append("\n}\n}");
                writer.write(stringBuffer.toString());
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                if(writer!=null){
                    try {
                        writer.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        return false;
    }


}
